HDU 5730 Shell Necklace(dp、cdq分治+FFT)
题意:
$给定N\le 10^5个贝壳的项链,每连续i\le N个贝壳模式的贡献是a_i$
$对于某种串项链的方式,假设含有模式b_1, b_2, \cdots, b_m,总贡献为\prod_{i=1}^m a_{b_i} $
$求所有串项链方式的贡献和$
分析:
$首先有显然的dp,f[i]:=以i结尾的贝壳的贡献和$
$f[i]=\sum_{j=1}^i f[i-j]\times a_j$
$但是转移是O(n)的,总复杂度是O(n^2),考虑优化$
$发现转移是个卷积形式,由于模数不是费马素数,所以cdq分治+FFT一波就好了$
$时间复杂度是O(nlog^2n)$
代码:
//
// Created by TaoSama on 2016-07-20
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
#include <complex>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 313;
const double PI = acos(-1);
int n, a[N];
int f[N];
typedef complex<double> Complex;
void rader(Complex* y, int len) {
for(int i = 1, j = len / 2; i < len - 1; i++) {
if(i < j) swap(y[i], y[j]);
int k = len / 2;
while(j >= k) {j -= k; k /= 2;}
if(j < k) j += k;
}
}
void fft(Complex* y, int len, int op) {
rader(y, len);
for(int h = 2; h <= len; h <<= 1) {
double ang = op * 2 * PI / h;
Complex wn(cos(ang), sin(ang));
for(int j = 0; j < len; j += h) {
Complex w(1, 0);
for(int k = j; k < j + h / 2; k++) {
Complex u = y[k];
Complex t = w * y[k + h / 2];
y[k] = u + t;
y[k + h / 2] = u - t;
w = w * wn;
}
}
}
if(op == -1) for(int i = 0; i < len; i++) y[i] /= len;
}
Complex A[N << 1], B[N << 1];
void cdq(int l, int r) {
if(l == r) return;
int mid = (l + r) >> 1;
cdq(l, mid);
int len = 1;
while(len <= r - l + 1) len <<= 1;
for(int i = 0; i < len; i++) {
A[i] = Complex(l + i <= mid ? f[l + i] : 0, 0);
B[i] = Complex(l + i + 1 <= r ? a[i + 1] : 0, 0);
}
fft(A, len, 1);
fft(B, len, 1);
for(int i = 0; i < len; i++) A[i] *= B[i];
fft(A, len, -1);
for(int i = mid + 1; i <= r; i++) {
f[i] += fmod(A[i - l - 1].real(), MOD) + 0.5;
if(f[i] >= MOD) f[i] -= MOD;
}
cdq(mid + 1, r);
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
clock_t _ = clock();
while(scanf("%d", &n) == 1 && n) {
for(int i = 1; i <= n; ++i) {
scanf("%d", a + i);
a[i] %= MOD;
}
memset(f, 0, sizeof f);
f[0] = 1;
cdq(0, n);
printf("%d\n", f[n]);
}
#ifdef LOCAL
printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
return 0;
}